// NOLINT
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/wait.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "<|>"

#define LINE_SIZE 1024
char line[LINE_SIZE]; // 用来存储输入的指令

// 分割指令集
#define SPACETOK " \t" // 指令分割符
#define ARGC_SIZE 32
char *argv[ARGC_SIZE]; // 命令行参数

#define EXIT_CODE 66 // 退出码设置为66
int lastcode = 0;

char pwd[LINE_SIZE];
char myenv[LINE_SIZE];  // 自定义一个环境变量表

// 获取用户名
const char *getUsername()
{
    return getenv("USER");
}

// 获取主机名
const char *getHostname()
{
    return getenv("HOSTNAME");
}

// 获取目录名
const char *getDirname()
{
    char *ret = strrchr(getenv("PWD"), '/'); // 利用strrchr函数查找最后一个‘/’
    if (*(ret + 1) != '\0')                  // 判断是否是根目录
        return ret + 1;
    return ret;
}

// 获取指令集
void getCommand(char *cline, int size)
{
    printf(LEFT "%s@%s %s" RIGHT LABLE " ", getUsername(), getHostname(), getDirname());
    char *s = fgets(cline, size, stdin);
    assert(s);
    (void)s;

    cline[strlen(cline) - 1] = '\0';        // 去掉结尾的 '\n'  "ls -l -a\n"
}

int splitstring(char *cline, char *_argv[])
{
    // 分割之前，将原来的_argv清空
    memset(_argv, '\0', ARGC_SIZE);
    char cp_line[LINE_SIZE] = {'\0'};
    for (int i = 0; cline[i] != '\0'; i++)
    {
        cp_line[i] = cline[i];
    }
    
    // ls -a -l
    int i = 0;
    char *ret = strtok(cp_line, SPACETOK);
    while (ret != NULL)
    {
        argv[i++] = ret;
        ret = strtok(NULL, SPACETOK);
    }

    // 特殊处理 ls （颜色化处理）
    if(strcmp(_argv[0], "ls") == 0)
    {
        _argv[i++] = "--color";
        _argv[i] =  NULL;
    }

    return i;       //判断是否有命令
}

// 普通命令的执行
void NormalExcute(char *_argv[])
{
    __pid_t id = fork();        //使用子进程执行相应的命令
    if (id < 0)
    {
        perror("fork()");
        return;
    }
    else if (id == 0)
    {
        // child
        // 让子进程执行对应的命令
        // 使用进程替换相关函数
        execvp(_argv[0], _argv);    // 第一个参数传主要命令，第二个参数传分割的命令集
        exit(EXIT_CODE);
    }
    else
    {
        // father
        int status = 0;
        __pid_t wid = waitpid(id, &status, 0);
        if (wid == id)
        {
            // 等待子进程成功
            lastcode = WEXITSTATUS(status); // 将退出结果返回过去
        }
    }
}

// 判断是否是内建命令
bool isBuildCommand(char* _argv[])
{
    if(strcmp(_argv[0], "cd") == 0
        || strcmp(_argv[0], "export") == 0
        || strcmp(_argv[0], "echo") == 0)
    {
        return true;
    }
    return false;
}

// 内建命令的执行
int BuildCommand(char* _argv[], int _argc)
{
    // 内建命令；cd、export、echo 等等
    if(_argc == 2 && strcmp(_argv[0], "cd") == 0)
    {
        chdir(argv[1]);     // 更改当前工作目录
        getcwd(pwd, sizeof(pwd));   // 获取路径到我定义的数组内
        sprintf(getenv("PWD"), "%s", pwd);  // 给环境变量pwd设置为pwd
        return 1;
    }
    else if(_argc == 2 && strcmp(_argv[0], "export") == 0)
    {
        // 增加环境变量
        strcpy(myenv, _argv[1]);    
        putenv(myenv);
        return 1;
    }
    else if(_argc == 2 && strcmp(_argv[0], "echo") == 0)
    {
        if(strcmp(_argv[1], "$?") == 0)
        {
            // printf("lastcode: %d\n", lastcode);
            lastcode = 0;
        }
        else if(*_argv[1] == '$')   //获取环境变量
        {
            char* val = getenv(_argv[1]+1);
            if(val)
                printf("%s\n", val);
        }
        else
        {
            printf("%s\n", _argv[1]);
        }
        
        return 1;
    }

    return 0;
}

int main()
{
    while (1)
    {
        // 获取指令集
        getCommand(line, sizeof(line));

        // 分割指令集
        int argc = splitstring(line, argv);        // 返回字串的个数
        
        if(isBuildCommand(argv))    // 判断是否是内建命令
            BuildCommand(argv, argc);     // 内建命令执行
        else        
            NormalExcute(argv);     // 普通命令执行

    }

    return 0;
}


// // 获取用户名
// const char *getUsername()
// {
//     return getenv("USER");
// }

// // 获取主机名
// const char *getHostname()
// {
//     return getenv("HOSTNAME");
// }

// // 获取目录名
// const char *getDirname()
// {
//     char *ret = strrchr(getenv("PWD"), '/'); // 利用strrchr函数查找最后一个‘/’
//     if (*(ret + 1) != '\0')                  // 判断是否是根目录
//         return ret + 1;
//     return ret;
// }

// #define LINE_SIZE 1024
// char line[LINE_SIZE]; // 用来存储输入的指令

// // 获取指令集
// void getCommand(char *cline, int size)
// {
//     printf(LEFT "%s@%s %s" RIGHT LABLE " ", getUsername(), getHostname(), getDirname());
//     char *s = fgets(cline, size, stdin);
//     assert(s);
//     (void)s;

//     cline[strlen(cline) - 1] = '\0';
// }

// // 分割指令集
// #define SPACETOK " \t" // 指令分割符
// #define ARGC_SIZE 32
// char *argv[ARGC_SIZE]; // 命令行参数
// int splitstring(char *cline, char *_argv[])
// {
//     // 分割之前，将原来的_argv清空
//     memset(_argv, '\0', ARGC_SIZE);
//     char cp_line[LINE_SIZE] = {'\0'};
//     for (int i = 0; cline[i] != '\0'; i++)
//     {
//         cp_line[i] = cline[i];
//     }
    
//     // ls -a -l
//     int i = 0;
//     char *ret = strtok(cp_line, SPACETOK);
//     while (ret != NULL)
//     {
//         argv[i++] = ret;
//         ret = strtok(NULL, SPACETOK);
//     }
//     return i - 1; // 返回字串的个数
// }

// // 普通命令的执行
// #define EXIT_CODE 66 // 退出码设置为66
// int lastcode = 0;
// void NormalExcute(char *_argv[])
// {
//     __pid_t id = fork();
//     if (id < 0)
//     {
//         perror("fork()");
//         return;
//     }
//     else if (id == 0)
//     {
//         // child
//         // 让子进程执行对应的命令
//         // 使用进程替换相关函数
//         execvp(_argv[0], _argv);
//         exit(EXIT_CODE);
//     }
//     else
//     {
//         // father
//         int status = 0;
//         __pid_t wid = waitpid(id, &status, 0);
//         if (wid == id)
//         {
//             // 等待子进程成功
//             lastcode = WEXITSTATUS(status); // 将退出结果返回过去
//         }
//     }
// }

// // 内建命令的执行
// int BuildCommand(char* _argv[], int _argc)
// {
//     // 内建命令；cd、export、echo 等等
//     if(_argc == 2 && strcmp(_argv[0], "cd") == 0)
//     {
//         chdir(argv[1]);
//         getpwd();
//         sprintf(getenv("PWD"), "%s", pwd);
//         return 1;
//     }
//     else if(_argc == 2 && strcmp(_argv[0], "export") == 0)
//     {
//         strcpy(myenv, _argv[1]);
//         putenv(myenv);
//         return 1;
//     }
//     else if(_argc == 2 && strcmp(_argv[0], "echo") == 0)
//     {
//         if(strcmp(_argv[1], "$?") == 0)
//         {
//             printf("%d\n", lastcode);
//             lastcode = 0;
//         }
//         else if(*_argv[1] == '$')
//         {
//             char* val = getenv(_argv[1]+1);
//             if(val)
//                 printf("%s\n", val);
//         }
//         else
//         {
//             printf("%s\n", _argv[1]);
//         }

//         return 1;
//     }

//     // 特殊处理 ls （颜色化处理）
//     // if(strcmp(_argv[0], "ls") == 0)
//     // {
//     //     _argv[_argc++] = "--color";
//     //     _argv[_argc] =  NULL;
//     // }
//     return 0;
// }

// int main()
// {
//     while (1)
//     {
//         // 获取指令集
//         getCommand(line, sizeof(line));

//         // 分割指令集
//         int argc = splitstring(line, argv);
        
//         // 内建命令
//         BuildCommand(argv, argc);

//         // 执行各指令
//         NormalExcute(argv);

//     }

//     return 0;
// }